package com.export.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.export.db.dbutils.UniqueID;
import com.export.entity.ReportExportLog;
import com.export.properties.FileServiceProperties;
import common.exec.RsjIllegalArgueException;
import common.statusenum.ExportLogEnum;
import common.util.DateTimeFormatterUtil;
import common.util.http.HttpUtil;
import common.util.http.UploadFileResponseBody;
import common.util.http.UploadFileResponseData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rsj.context.ApplicationContextUtil;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 导出
 *
 * @author yuanqinglong
 * @since 2021/7/28 10:24
 */
public interface IExportService {

    Logger logger = LoggerFactory.getLogger(IExportService.class);



    /**
     * 保存日志创建excel上传
     *
     * @param data       数据
     * @param type       类型
     * @param fileName   文件名称
     * @param operatorId 操作人id
     */
    default void saveLogCreateExcelUpload(List<?> data, Class<?> type, String fileName, String operatorId) {
        // 将文件上传到文件服务器 返回文件id
        UploadFileResponseData fileResponseData;
        fileName += DateTimeFormatterUtil.dateTimeToSimpleString(LocalDateTime.now()) + ".xlsx";
        // 保存日志
        ReportExportLog reportExportLog = new ReportExportLog(String.valueOf(UniqueID.generateId()), null,
                fileName, ExportLogEnum.BUILDING.getCode(), LocalDateTime.now(), LocalDateTime.now(), operatorId);
        this.saveExportLog(reportExportLog);
        try {
            OutputStream outputStream = this.writeDataToTheOutputStream(data, type);
            // 生成文件名称
            // 上传到文件服务器
            fileResponseData = this.uploadToFileService(outputStream, fileName);
            reportExportLog.setFileCreateStatus(ExportLogEnum.GENERATED.getCode());
            reportExportLog.setExportFileId(fileResponseData.getFileId());
            // 上传成功更新日志状态
            this.updateExportLogStatus(reportExportLog);
        } catch (Exception e) {
            reportExportLog.setFileCreateStatus(ExportLogEnum.FAILED_TO_BUILD.getCode());
            this.updateExportLogStatus(reportExportLog);
            logger.error("导出 {}失败：", fileName, e);
        }
    }


    /**
     * 写数据到输出流
     *
     * @param data 数据
     * @param type 类型
     * @return {@link OutputStream}
     */
    default OutputStream writeDataToTheOutputStream(List<?> data, Class<?> type) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        EasyExcel.write(outputStream, type).autoCloseStream(true).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(data);
        return outputStream;
    }


    /**
     * 保存导出日志
     *
     * @param reportExportLog 报告导出日志
     */
    default void saveExportLog(ReportExportLog reportExportLog) {
        IMyExportService myExportService = ApplicationContextUtil.getBean(IMyExportService.class,"myExportServiceImpl");
        myExportService.saveExportLog(reportExportLog);
    }


    /**
     * 修改日志状态
     *
     * @param reportExportLog 报告导出日志
     */
    default void updateExportLogStatus(ReportExportLog reportExportLog) {
        IMyExportService myExportService = ApplicationContextUtil.getBean(IMyExportService.class,"myExportServiceImpl");
        myExportService.updateExportLog(reportExportLog);
    }


    /**
     * 将生成的文档上传到文件服务
     *
     * @param outputStream   文件输出流
     * @param exportFileName 导出的文件名称
     * @return 文件服务返回的文件id
     */
    default UploadFileResponseData uploadToFileService(OutputStream outputStream, String exportFileName) {
        String uploadUrl = ApplicationContextUtil.getBean(FileServiceProperties.class).getFileServiceUploadUrl();
        UploadFileResponseBody responseBody = HttpUtil.uploadFile(uploadUrl, exportFileName, "$file", outputStreamToInputStream(outputStream));
        return Optional.ofNullable(responseBody).map(UploadFileResponseBody::getData).orElseThrow(() -> new RsjIllegalArgueException("文件生成失败"));
    }


    /**
     * OutputStream转InputStream
     *
     * @param out 输出流
     * @return 输入流
     */
    static ByteArrayInputStream outputStreamToInputStream(OutputStream out) {
        ByteArrayOutputStream byteArrayOutputStream = (ByteArrayOutputStream) out;
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

}
